package com.ymx.darling.executor.mapping.handler;

import com.ymx.darling.bean.sql.Statement;
import com.ymx.darling.exception.ResultSetException;
import com.ymx.darling.executor.mapping.metadata.MetaData;
import com.ymx.darling.executor.mapping.metadata.MetaDataManager;
import com.ymx.darling.type.TypeHandlerRegister;
import com.ymx.darling.type.TypeHandler;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

/**
 * 将结果集中的一列数据放入集合中返回
 * 如果结果集中有多列数据 将抛出异常
 * @author 爱Java的小于
 */
public class ObjectResultSetHandler<T> implements ResultSetHandler<T> {
    private final Statement statement;
    private final TypeHandler<T> typeHandler;
    private boolean checkCursorResultSetIsOnlyOneColumnEnabled = true; //是否开启游标结果集的字段数量进行检查

    public ObjectResultSetHandler(Statement statement) {
        this.statement = statement;
        this.typeHandler = (TypeHandler<T>)TypeHandlerRegister.getTypeHandler(statement.getModule());
    }


    @Override
    public List<T> handle(ResultSet resultSet) throws SQLException {
        this.checkOnlyOneColumn(resultSet);
        return this.doMapping(resultSet);
    }


    /**
     * 检查结果集只有一列数据
     * @param resultSet 结果集
     */
    private void checkOnlyOneColumn(ResultSet resultSet) throws SQLException {
        List<MetaData> metaData = MetaDataManager.getMetaDataList(resultSet);
        if (metaData.size() > 1) {
            throw new ResultSetException(String.format("结果集异常: 结果集数据只能为一列数据,无法将多列数据放入'%s'. 错误的列数:%d", statement.getModule().getName(), metaData.size()));
        }
    }


    @Override
    public T handleCursor(ResultSet resultSet) throws SQLException {
        if (this.checkCursorResultSetIsOnlyOneColumnEnabled) {
            this.checkOnlyOneColumn(resultSet);
            this.checkCursorResultSetIsOnlyOneColumnEnabled = false;
        }
        return this.typeHandler.getResult(resultSet, 0);
    }


    /**
     * 执行映射
     * @param resultSet 结果集
     * @return list
     * @throws SQLException 可能会抛出此异常
     */
    private List<T> doMapping(ResultSet resultSet)throws SQLException {
        List<T> resultSetList = new ArrayList<>();
        while (resultSet.next()) {
            resultSetList.add(this.typeHandler.getResult(resultSet, 1));
        }

        return resultSetList;
    }
}
